#ifndef __M_CONNECT_H__
#define __M_CONNECT_H__

#include "channel.hpp"

namespace mmq
{
    class Connection
    {
    public:
        using ptr = std::shared_ptr<Connection>;
    public:
        Connection(const ConsumerManager::ptr &cmp,
            const VirtualHost::ptr &host, 
            const ProtobufCodecPtr &codec, 
            const muduo::net::TcpConnectionPtr &conn,
            const Threadpool::ptr &pool)
            : _conn(conn), _codec(codec), _cmp(cmp), _host(host), _pool(pool),
            _channels(std::make_shared<ChannelManager>())
        {}
        void OpenChannel(const OpenChannelRequestPtr &req)
        {
            bool ret = _channels->OpenChannel(req->cid(), _cmp, _host, _codec, _conn, _pool);
            if(ret == false)
            {
                DLOG("创建信道时，信道ID重复了");
                BasicResponse(req->rid(), req->cid(), false);
            }
            BasicResponse(req->rid(), req->cid(), true);
        }
        void CloseChannel(const CloseChannelRequestPtr &req)
        {
            _channels->CloseChannel(req->cid());
            BasicResponse(req->rid(), req->cid(), true);
        }

        Channel::ptr GetChannel(const std::string &id)
        {
            return _channels->GetChannel(id);
        }
    private:
        void BasicResponse(const std::string &rid, const std::string &cid, bool ok)
        {
            BasicCommonResponse resp;
            resp.set_rid(rid);
            resp.set_cid(cid);
            resp.set_ok(ok);
            _codec->send(_conn, resp);
        }
    private:
        muduo::net::TcpConnectionPtr _conn;
        ProtobufCodecPtr _codec;
        ConsumerManager::ptr _cmp;
        VirtualHost::ptr _host;
        Threadpool::ptr _pool;
        ChannelManager::ptr _channels;
    };

    class ConnectManager
    {
    public:
        using ptr = std::shared_ptr<ConnectManager>;
    public:
        ConnectManager()
        {}
        void NewConnection(const ConsumerManager::ptr &cmp,
            const VirtualHost::ptr &host, 
            const ProtobufCodecPtr &codec, 
            const muduo::net::TcpConnectionPtr &conn,
            const Threadpool::ptr &pool)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _conns.find(conn);
            if(it != _conns.end())
                return;
            Connection::ptr self_conn = std::make_shared<Connection>(cmp, host, codec, conn, pool);
            _conns.insert({conn, self_conn});
        }
        void DelConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _conns.erase(conn);
        }   
        Connection::ptr GetConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _conns.find(conn);
            if(it == _conns.end())
            {
                return Connection::ptr();
            }
            return it->second;
        }
    private:
        std::mutex _mutex;
        std::unordered_map<muduo::net::TcpConnectionPtr, Connection::ptr> _conns;
    };
}

#endif